import datetime
from typing import Optional

import pandas as pd
from fastapi import APIRouter, Query
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse

from pojo.response import Response
from service import dataService
from service.strategyService import Movement
from utils.utils import is_empty

dataRouter = APIRouter(tags=['data'])


@dataRouter.get('/stock/get_stockInfoList', summary='获得股票信息列表')
async def get_stockInfoList():
    ls, _ = await dataService.get_stockInfoList()

    if ls is None:
        code = 0
        message = '获取股票信息列表失败'
    else:
        code = 1
        message = '获取股票信息列表成功'


    return Response(
        code=code,
        message=message,
        data=ls
    )

@dataRouter.get('/stock/get_stockIndexList', summary='获得成分股列表')
async def get_stockIndexList(
        index_symbol: str = Query(description="成分股代码"),
):
    ls, _ = await dataService.get_stockIndexList(index_symbol=index_symbol)

    if ls is None:
        code = 0
        message = '获取成分股信息列表失败'
    else:
        code = 1
        message = '获取成分股信息列表成功'

    return Response(
        code=code,
        message=message,
        data=ls
    )


@dataRouter.get('/stock/get_stockPriceList',
                summary='获得单个股票的行情数据',
                description="""
                * 输入(code(股票代码), start_date(开始日期-'20210101'), end_date(结束日期-'20250101'), window(时间窗口-int))
                * 只输入code, 则返回'20210101'至今天的信息
                * 不输入end_date,返回start_date至今天的信息
                * 输入window, start_date和end_date, 计算从昨天算起window天的信息
                """
                )
async def get_stockPriceList(
        code: str = Query(description='股票代码'),
        start_date: Optional[str] = Query(None, description='起始日期'),
        end_date: Optional[str] = Query(None, description='结束日期'),
        window: Optional[str] = Query(None, description='时间窗口')
):

    # 参数处理部分 默认值处理 window还需要处理int转换
    if isinstance(start_date, str) and start_date=='':
        start_date = None

    if isinstance(end_date, str) and end_date=='':
        end_date = None

    if isinstance(window, str):
        if window=='':
            window = None
        else:
            window = int(window)

    ls, _  = await dataService.get_stockPriceList(
        code=code,
        start_date=start_date,
        end_date=end_date,
        window=window
    )

    if ls is None:
        code = 0
        message = '获取单个股票的行情数据失败'
    else:
        code = 1
        message = '获取单个股票的行情数据成功'

    return Response(
        code=code,
        message=message,
        data=ls
    )


@dataRouter.get('/stock/get_stockHistList',
                summary='获得单个股票的历史分时数据')
async def get_stockHistList(
        code: str = Query(description='股票代码'),
        start_date: str = Query(description='起始日期'),
        end_date: str = Query(description='结束日期'),
        period: Optional[str] = Query('15', description="周期 {'1', '5', '15', '30', '60'}")
):
    # 参数处理部分 默认值
    if isinstance(period, str) and period=='':
        period = '15'

    ls, _ = await dataService.get_stockHistList(
        code=code,
        start_date=start_date,
        end_date=end_date,
        period=period
    )

    if ls is None:
        code = 0
        message = '获取单个股票的历史分时数据失败'
    else:
        code = 1
        message = '获取单个股票的历史分时数据成功'

    return Response(
        code=code,
        message=message,
        data=ls
    )


@dataRouter.get('/chip/get_stockChipList',
                summary='获取单个股票在时间窗口内的筹码数据')
async def get_stockChipList(
        code: str = Query(description='股票代码'),
        window: str = Query(description='时间窗口')
):
    # 参数处理部分
    if isinstance(code, str) and is_empty(code):
        return Response(
            code=0,
            message='参数错误! 股票代码不能为空'
        )

    if isinstance(window, str):
        if is_empty(window):
            return Response(
                code=0,
                message='参数错误! 时间窗口不能为空'
            )
        else:
            window = int(window)

    ls, _ = await dataService.get_stockChipList(code=code, window=window)
    if ls is None:
        code = 0
        message = '获取单个股票的筹码数据失败'
    else:
        code = 1
        message = '获取单个股票的筹码数据成功'

    return Response(
        code=code,
        message=message,
        data=ls
    )


@dataRouter.get('/date/get_tradeDateList',
                summary='获得时间窗口内的交易日')
async def get_tradeDateList(
        window: str = Query(description='时间窗口')
):

    # 参数处理部分
    if isinstance(window, str) and window!='':
        window = int(window)
    else:
        return Response(
            code=0,
            message='参数错误'
    )

    ls = await dataService.get_tradeDateList(window=window)

    if ls is None:
        code = 0
        message = '获得时间窗口内的交易日数据失败'
    else:
        code = 1
        message = '获得时间窗口内的交易日数据成功'

    return Response(
        code=code,
        message=message,
        data=ls
    )

@dataRouter.get('/stock/get_stockBidList',
                summary='获得股票实时行情列表')
async def get_stockBidList(
        code: str = Query(description='股票代码')
):
    dict_, _ = await dataService.get_stockBidList(code)

    if dict_ is None:
        code = 0
        message = '获得股票实时行情列表失败'
    else:
        code = 1
        message = '获得股票实时行情列表成功'

    return Response(
        code=code,
        message=message,
        data=dict_
    )

@dataRouter.get('/stock/get_stockSpotList',
                summary='获取股票实时行情列表(带交易量)')
async def get_stockSpotList(
        code: str = Query("", description="股票代码")
):
    if isinstance(code, str) and code=='':
        code = None
    dict_, _ = await dataService.get_SpotList(code=code)

    if dict_ is None:
        code = 0
        message = '获得股票实时行情列表失败'
    else:
        code = 1
        message = '获得股票实时行情列表成功'

    return Response(
        code=code,
        message=message,
        data=dict_
    )


@dataRouter.get('/stock/get_stockIntradayMovement',
                summary='获得股票的日内动量数据',
                description='返回噪声区的上下边界')
async def get_stockIntradayMovement(
        code: str = Query(description='股票代码'),
        window: Optional[str] = Query('14', description='时间窗口, 默认为14天'),
        period: Optional[str] = Query('15', description='周期, 默认为15分钟 可选15 30')
):
    # 处理参数 默认值
    if isinstance(window, str):
        if window=='':
            window = 14
        else:
            window = int(window)

    if isinstance(period, str) and period=='':
            period = '15'

    # 获得时间窗口内的交易日
    trade_days = await dataService.get_tradeDateList(window=window)
    start_date = trade_days[0]
    end_date = trade_days[-1]

    # 获取时间窗口内的分时数据

    _, df = await dataService.get_stockHistList(
        code=code,
        start_date=start_date,
        end_date=end_date,
        period=period
    )

    if df is None:
        Response(
            code=0,
            message='日内动量数据获取失败'
        )

    # 获得日内动量数据
    model = Movement.IntradayMovementStrategy(period=period, window=window, code=code)
    (upperBound_ls, lowerBound_ls), _ = await model.analyze(df)

    return Response(
        code=1,
        message='日内动量数据获成功',
        data={
            'UpperBound': upperBound_ls,
            'LowerBound': lowerBound_ls,
        }
    )

@dataRouter.get('/movement/getStockIntradayMovementWithDate',
                    summary='某天的日内动量分析策略',
                    description='返回代表上下边界的坐标点列表以及时间间隔的价格')
async def get_stockIntradayMovementWithDate(
        code: str = Query(description='股票代码'),
        window: Optional[str] = Query('14', description='时间窗口, 默认为14天'),
        period: Optional[str] = Query('15', description='周期, 默认为15分钟 可选15 30'),
        date: str = Query(description='某天的时间, 如20240701')
):
    # 参数非空处理
    if isinstance(code, str) and code=='':
        return Response(
            code=0,
            message="参数错误: 股票代码参数不能为空!"
        )

    if isinstance(date, str) and date=='':
        return Response(
            code=0,
            message="参数错误: 日期参数不能为空!"
        )

    # 处理参数 window 需要转换int
    if isinstance(window, str):
        if window=='':
            window = 14
        else:
            window = int(window)
    # 默认值处理 前端可能发送''
    if isinstance(period, str) and period=='':
        period = '15'

    # 获得时间窗口内的交易日 最后一天就是昨天
    trade_days = await dataService.get_tradeDateList(window=window, date=datetime.datetime.strptime(date, "%Y%m%d").date())
    start_date = trade_days[0]
    end_date = trade_days[-1]

    # 获取时间窗口内的分时数据
    _, df = await dataService.get_stockHistList(
        code=code,
        start_date=start_date,
        end_date=end_date,
        period=period
    )

    if df is None:
        return JSONResponse(jsonable_encoder(Response(
            code=0,
            message='获取数据失败'
        )))

    # 获得日内动量数据
    model = Movement.IntradayMovementStrategy(period=period, window=window, code=code)
    (upperBound_ls, lowerBound_ls), _ = await model.analyze(df)

    # 获得date日的日内分时价格
    intraday_price_ls, intraday_price_df = await dataService.get_stockHistList(
        code=code,
        start_date=date,
        end_date=date,
        period=period
    )

    if intraday_price_df is None:
        code = 0
        message = '获取日内时间间隔交易数据失败'
    else:
        intraday_price_df.index = pd.to_datetime(intraday_price_df.index)

        intraday_price_ls = {
            t.strftime('%H:%M:%S'): v for t, v in intraday_price_df['close'].items()
        }
        code = 1
        message = '获取日内时间间隔交易数据成功'

    return Response(
        code=code,
        message=message,
        data={
            'UpperBound': upperBound_ls,
            'LowerBound': lowerBound_ls,
            'IntradayPrice': intraday_price_ls,
        }
    )